package com.wxd.woff.table.glyf;

import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Description: 功能描述：将点转为坐标
 * @ClassName: GlyphRenderer
 * @author: Wang Xindong
 * @date: 2018年9月6日 下午12:06:16
 * @email: wangxindong@travelsky.com
 * @Copyright: Copyright (c) 2018. All rights reserved.
 */
public class GlyphRenderer {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlyphRenderer.class);

    private AbstractGlyfDescript glyfDescript;

    public GlyphRenderer(AbstractGlyfDescript glyfDescript) {
        this.glyfDescript = glyfDescript;
    }

    public GeneralPath getPath() {
        Point[] points = describe(glyfDescript);
        return calculatePath(points);
    }

    public Point[] describe() {
        int endPtIndex = 0;
        int endPtOfContourIndex = -1;
        Point[] points = new Point[glyfDescript.getPointCount()];
        for (int i = 0; i < glyfDescript.getPointCount(); i++) {
            if (endPtOfContourIndex == -1) {
                endPtOfContourIndex = glyfDescript.getEndPtOfContours(endPtIndex);
            }
            boolean endPt = endPtOfContourIndex == i;
            if (endPt) {
                endPtIndex++;
                endPtOfContourIndex = -1;
            }
            points[i] = new Point(glyfDescript.getXCoordinate(i), glyfDescript.getYCoordinate(i),
                    (glyfDescript.getFlags(i) & AbstractGlyfDescript.ON_CURVE) != 0, endPt);
        }
        return points;

    }

    /**
     * 获取表的坐标点位
     */
    @Deprecated
    public Point[] describe(GlyphDescription gd) {
        int endPtIndex = 0;
        int endPtOfContourIndex = -1;
        Point[] points = new Point[gd.getPointCount()];
        for (int i = 0; i < gd.getPointCount(); i++) {
            if (endPtOfContourIndex == -1) {
                endPtOfContourIndex = gd.getEndPtOfContours(endPtIndex);
            }
            boolean endPt = endPtOfContourIndex == i;
            if (endPt) {
                endPtIndex++;
                endPtOfContourIndex = -1;
            }
            points[i] = new Point(gd.getXCoordinate(i), gd.getYCoordinate(i),
                    (gd.getFlags(i) & AbstractGlyfDescript.ON_CURVE) != 0, endPt);
        }
        return points;
    }

    /**
     * Use the given points to calculate a GeneralPath.
     *
     * @param points the points to be used to generate the GeneralPath
     * @return the calculated GeneralPath
     */
    private GeneralPath calculatePath(Point[] points) {
        GeneralPath path = new GeneralPath();
        int start = 0;
        for (int p = 0, len = points.length; p < len; ++p) {
            if (points[p].isEndOfContour()) {
                Point firstPoint = points[start];
                Point lastPoint = points[p];
                List<Point> contour = new ArrayList<>();
                for (int q = start; q <= p; ++q) {
                    contour.add(points[q]);
                }
                if (points[start].isOnCurve()) {
                    // using start point at the contour end
                    contour.add(firstPoint);
                } else if (points[p].isOnCurve()) {
                    // first is off-curve point, trying to use one from the end
                    contour.add(0, lastPoint);
                } else {
                    // start and end are off-curve points, creating implicit one
                    Point pmid = midValue(firstPoint, lastPoint);
                    contour.add(0, pmid);
                    contour.add(pmid);
                }
                moveTo(path, contour.get(0));
                for (int j = 1, clen = contour.size(); j < clen; j++) {
                    Point pnow = contour.get(j);
                    if (pnow.isOnCurve()) {
                        lineTo(path, pnow);
                    } else if (contour.get(j + 1).isOnCurve()) {
                        quadTo(path, pnow, contour.get(j + 1));
                        ++j;
                    } else {
                        quadTo(path, pnow, midValue(pnow, contour.get(j + 1)));
                    }
                }
                path.closePath();
                start = p + 1;
            }
        }
        LOGGER.info("坐标：{}", path);
        return path;
    }

    private void moveTo(GeneralPath path, Point point) {
        path.moveTo(point.getX(), point.getY());
    }

    private void lineTo(GeneralPath path, Point point) {
        path.lineTo(point.getX(), point.getY());
    }

    private void quadTo(GeneralPath path, Point ctrlPoint, Point point) {
        path.quadTo(ctrlPoint.getX(), ctrlPoint.getY(), point.getX(), point.getY());
    }

    private int midValue(int a, int b) {
        return a + (b - a) / 2;
    }

    private Point midValue(Point point1, Point point2) {
        return new Point(midValue(point1.getX(), point2.getX()), midValue(point1.getY(), point2.getY()));
    }
}
